package com.bcx.crm.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Created by ys on 2017/12/12.
 */
//切面的标志,aop的代理会找到这个标志(如果注解和xml配置有重合,则不执行.)
@Aspect
@Component
public class AspectAnnotation {
//    @Pointcut("execution(* com.bcx.crm.spring.aop.Performance.*(java.lang.String))")
//    @Pointcut("execution(* com.bcx.crm.spring.aop.*.*(..))")//指定路径为包
//    @Pointcut("within(com.bcx.crm.spring.aop.*)")//aop包下的任意连接点-->
//    @Pointcut("within(com.bcx.crm.spring..*)")//spring包下的任意连接点-->
//    @Pointcut("bean(artist)")//bean可以指定IOC容器中的bean的名称
//    @Pointcut("execution(* com.bcx.crm.spring.aop.Performance.*(..))")//具体到一个类或者接口
//    @Pointcut("execution(* com.bcx.crm.spring..*.*(..))")//..(两个点)表示零个或多个，上面的第一个..表示spring包及其子包
    @Pointcut("execution(* com.bcx.crm.spring.aop.Performance.*(..))")
    public void pointCut(){

    }
    @Around("pointCut()")
    @Order(1)
    //进入around之后就不再进入before和切点方法,除非不用around或者joinPoint.proceed()执行目标方法
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();//获取切点的参数值
        System.out.println("around->");
        Signature sig = joinPoint.getSignature();//获取切点的方法及其信息(切点所在的类,不是切点类所对的接口)
        MethodSignature msig=null;
        if (! (sig instanceof MethodSignature)){
            throw new IllegalStateException("该注解只能用于方法");
        }
        msig=(MethodSignature)sig;//切点的方法及其信息
        Object target = joinPoint.getTarget();//切点所在的类,本例中是Artist,可以调用方法(需要强制转换):target.方法名
        Method method = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        //知识点2
        Object proceed = joinPoint.proceed();//执行目标方法,否则通知方法执行了但目标方法没执行
        return proceed;//"123"
    }

    @Before(value = "pointCut()")
    @Order(0)
    public void before(JoinPoint joinPoint){
        //开启事物
        System.out.println("before:表演之前先准备");
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint){
        System.out.println("after:表演之后开始收拾东西");
    }

    @AfterReturning(pointcut = "pointCut()",returning = "pointResult")
    public void afterReturning(Object pointResult){
        //pointcut与value属性功能一样,当指定了pointcut属性值后，value属性值将会被覆盖
        //声明pointResult时指定的类型会限制目标方法必须返回指定类型的值或没有返回值
        System.out.println("获取目标方法返回值:"+pointResult);//返回值测试失败
        System.out.println("afterReturning:东西收拾好了");
    }

    @AfterThrowing(value = "pointCut()",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();//类的路径与名称
        String name = joinPoint.getSignature().getName();//方法名
        Throwable throwable1 = throwable.fillInStackTrace();//异常
        System.out.println("afterThrowing:"+declaringTypeName+"."+name+"抛出了"+throwable1+"类型的异常");
        //举例:afterThrowing:com.bcx.crm.spring.aop.Artist.performance抛出了java.lang.IndexOutOfBoundsException: Index: 5, Size: 2类型的异常
    }
}
